// Copyright 2010 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.android.apps.moderator;

import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.Window;
import android.view.MenuItem.OnMenuItemClickListener;
import android.widget.ListView;
import android.widget.Toast;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Allows the user to navigate the contents of a Moderator Topic
 */
public class TopicActivity extends RefreshableActivity {

  protected String TAG = TopicActivity.class.getName();
  
  private static final int MAX_RESULTS = 20;

  /**
   * The synchronizer for the list
   */
  private ListSynchronizer listSynchronizer;

  // The largest known vote count sets the scale for all the submissions
  int maxBarVotes = 0;
  
  /**
   * The list has more contextual information on it if it is externally
   * launched. This would be repetitious and redundant if the user navigated
   * inside the app.
   */
  private boolean launchedFromOutsideApp;

  void getSubmissions(int seriesId, int topicId, int offset, List<ListEntry> items,
      Map<Integer, JSONObject> votesBySubmissionId, ListSynchronizer listSynchronizer)
      throws AccessException, JSONException {
    
    // Get the data from the API
    JSONObject submissions = getJsonData(API_URL_BASE + "series/" + seriesId
        + "/topics/" + topicId + "/submissions?start-index=" + offset
        + "&max-results=" + MAX_RESULTS);
    
    // Get the array of items in the data returned by the API
    JSONObject data = submissions.getJSONObject("data");
    if (data.has("items")) {
      JSONArray submissionItems = data.getJSONArray("items");
  
      // Add the submissions from the JSON data returned by the API
      int numberSubmissions = submissionItems.length();
      for (int idx = 0; idx != numberSubmissions; idx++) {
        JSONObject submission = submissionItems.getJSONObject(idx);
        int submissionId = submission.getJSONObject("id").getInt("submissionId");
        SubmissionListEntry question =
            new SubmissionListEntry(submission, votesBySubmissionId.get(submissionId), topicId);
        items.add(question);
        maxBarVotes =
            Math.max(maxBarVotes, Math.max(question.getMinusVotes(), question.getPlusVotes()));
      }
  
      // Set the votes on the submissions
      for (ListEntry listEntry : items) {
        if (listEntry instanceof SubmissionListEntry) {
          SubmissionListEntry question = (SubmissionListEntry) listEntry;
          question.setMaxBarVotes(maxBarVotes);
        }
      }
  
      if (numberSubmissions == MAX_RESULTS) {
        // In the event that the list is exactly MAX_RESULTS long, the subsequent request will
        // return zero results which will clear the spinner.
        items.add(new MoreSubmissionsListEntry(seriesId, topicId, offset + submissionItems.length(),
            listSynchronizer, votesBySubmissionId));
      }
    } else {
      // TODO: provide permanant prompt on screen about the empty list
      runOnUiThread(new Runnable() {
        public void run() {
          Toast.makeText(TopicActivity.this, getResources().getString(R.string.no_submissions),
              TOAST_DURATION).show();
          hideProgress();
        }
      });

    }
  }
  
  @Override
  protected void onCreate(Bundle savedInstanceState) {

    String name = getIntent().getStringExtra("name");

    // Internally the 'name' extra is set
    launchedFromOutsideApp = (name == null);

    if (launchedFromOutsideApp) {
      // The title is replaced by a full description of the topic
      requestWindowFeature(Window.FEATURE_NO_TITLE);
    } else {
      setTitle(name);
    }

    setContentView(R.layout.topic);

    ListView listView = (ListView) findViewById(R.id.Content);
    List<Integer> list = new ArrayList<Integer>();
    list.add(R.layout.topic_entry);
    list.add(R.layout.submission_entry);
    list.add(R.layout.more_submissions_entry);
    listSynchronizer = new ListSynchronizer(this, listView, list);

    refresh();
    super.onCreate(savedInstanceState);
  }

  @Override
  public boolean onPrepareOptionsMenu(Menu menu) {
    if (!super.onPrepareOptionsMenu(menu)) {
      return false;
    }
    //'New submission' menu item
    MenuItem refresh = menu.add(R.string.new_submission);
    refresh.setIcon(android.R.drawable.ic_menu_add);
    refresh.setOnMenuItemClickListener(new OnMenuItemClickListener() {

      public boolean onMenuItemClick(MenuItem item) {
        Intent intent = new Intent(TopicActivity.this, UserSubmissionActivity.class);
        intent.putExtra("seriesId", getIntent().getIntExtra("seriesId", -1));
        intent.putExtra("topicId", getIntent().getIntExtra("topicId", -1));
        intent.putExtra("topicName", getIntent().getStringExtra("name"));
        startActivity(intent);
        return false;
      }
    });
    return true;
  } 
  
  @Override
  protected void onRestart() {
    // Back button pressed, probably
    refresh();
    super.onRestart();
  }

  /**
   * Build the Topic list from data obtained from the API server
   */
  @Override
  void refresh() {
    showProgress();

    /**
     * Fetch is done on thread so as not to block the UI
     */
    new Thread(new Runnable() {
      public void run() {
        try {
          // Pull the IDs out of the extras
          int seriesId = getIntent().getIntExtra("seriesId", -1);
          int topicId = getIntent().getIntExtra("topicId", -1);

          // Build a list of entries
          final List<ListEntry> items = new ArrayList<ListEntry>();

          if (launchedFromOutsideApp) {
            // Add the topic header, having obtained it from the API
            JSONObject topic =
                getJsonData(API_URL_BASE + "series/" + seriesId + "/topics/" + topicId);
            items.add(new TopicListEntry(topic.getJSONObject("data"), true));
          }
          
          // Votes are cross referenced by submission ID for a join between votes and submissions
          Map<Integer, JSONObject> votesBySubmissionId = new HashMap<Integer, JSONObject>();

          if (!"".equals(LoginActivity.getAuthToken(TopicActivity.this))) {

            JSONObject votes = getJsonData(API_URL_BASE + "series/" + seriesId + "/votes/@me");

            JSONArray voteItems = votes.getJSONObject("data").optJSONArray("items");

            if (voteItems != null) {
              for (int idx = 0; idx != voteItems.length(); idx++) {
                JSONObject vote = voteItems.getJSONObject(idx);
                votesBySubmissionId.put(vote.getJSONObject("id").getInt("submissionId"), vote);
              }
            }
          }

          getSubmissions(seriesId, topicId, 0, items, votesBySubmissionId, listSynchronizer);
          
          // Apply the new list
          listSynchronizer.setEntries(items);

          hideProgress();
        } catch (final AuthenticationProblem e) {
          runOnUiThread(new Runnable() {
            public void run() {
              Toast.makeText(TopicActivity.this, getResources().getString(R.string.please_sign_in),
                  TOAST_DURATION).show();
              hideProgress();
            }
          });
          startActivity(new Intent(TopicActivity.this, LoginActivity.class));
        } catch (final AccessException e) {
          generalError(e, R.string.connection_problem);
        } catch (JSONException e) {
          generalError(e, R.string.a_problem_occurred);
        }

      }

    }).start();
  }
}
